//
// Created by dukang wang on 2025/1/4.
//

#include "../include/AudioPlayer.h"

namespace hy {

    AudioPlayer::AudioPlayer() {
        this->dataQueue = new DataQueue();
        this->dataQueue->setWork(1);
    }

    AudioPlayer::~AudioPlayer() {
        release();
    }


    /**
     * 回调函数，从队列里面取数据，加入队列播放
     */
    void pcmBufferCallBack(SLAndroidSimpleBufferQueueItf bf, void *context) {
        LOGI("pcmBufferCallBack ok")

        AudioPlayer *audioPlayer = static_cast<AudioPlayer *>(context);
        if (audioPlayer == NULL) {
            LOGE("pcmBufferCallBack audioPlayer is NULL")
            return;
        }

        PcmData *data = audioPlayer->dataQueue->getPcmData();
        if (data != NULL) {
            LOGI("pcmBufferCallBack PcmData size=%d", data->getSize())
            (*audioPlayer->pcmBufferQueue)->Enqueue(
                    audioPlayer->pcmBufferQueue,
                    data->getData(),
                    data->getSize()
            );

        } else {
            LOGE("pcmBufferCallBack PcmData is NULL")
        }

    }

    void *p_play(void *context) {
        AudioPlayer *audioPlayer = static_cast<AudioPlayer *>(context);

        /***********  5 设置播放器回调 ***********/
        SLresult result = (*audioPlayer->pcmBufferQueue)->RegisterCallback(
                audioPlayer->pcmBufferQueue,
                pcmBufferCallBack,
                audioPlayer);
        if (result != SL_RESULT_SUCCESS) {
            LOGE("pcmBufferQueue RegisterCallback failed result=%d", result)
        }

        LOGE("pcmPlayerPlay SetPlayState SL_PLAYSTATE_PLAYING start")
        //设置播放状态
        (*audioPlayer->pcmPlayerPlay)->SetPlayState(
                audioPlayer->pcmPlayerPlay,
                SL_PLAYSTATE_PLAYING);

        LOGE("pcmPlayerPlay SetPlayState SL_PLAYSTATE_PLAYING end")

        //启动
        pcmBufferCallBack(audioPlayer->pcmBufferQueue, audioPlayer);

        LOGE("pthread_exit start")
        pthread_exit(&audioPlayer->play_thread_t);
        LOGE("pthread_exit end")
    }

    int AudioPlayer::Init(int sample_rate) {
        this->sample_rate = sample_rate;

//        struct timeval t_start, t_end;
//        gettimeofday(&t_start, NULL);
//        LOGI("Start time: %ld us", t_start.tv_usec)

        /***********  1 创建引擎 获取SLEngineItf ***********/
        SLresult result;
        result = slCreateEngine(&engineObject, 0, 0, 0, 0, 0);
        if (result != SL_RESULT_SUCCESS) {
            LOGE("slCreateEngine create engineObject failed result=%d", result)
            return -1;
        }

        result = (*engineObject)->Realize(engineObject, SL_BOOLEAN_FALSE);
        if (result != SL_RESULT_SUCCESS) {
            LOGE("engineObject Realize failed result=%d", result)
            return -1;
        }

        result = (*engineObject)->GetInterface(engineObject, SL_IID_ENGINE, &engineEngine);
        if (result != SL_RESULT_SUCCESS) {
            LOGE("engineObject GetInterface engineEngine failed result=%d", result)
            return -1;
        }

        if (!engineEngine) {
            LOGE("engineObject GetInterface engineEngine failed, engineEngine is NULL ")
            return -1;
        }


        /***********  2 创建混音器 ***********/
        const SLInterfaceID mids[1] = {SL_IID_ENVIRONMENTALREVERB};
        const SLboolean mreq[1] = {SL_BOOLEAN_FALSE};
        result = (*engineEngine)->CreateOutputMix(engineEngine, &outputMixObject, 1, mids, mreq);
        if (result != SL_RESULT_SUCCESS) {
            LOGE("engineEngine CreateOutputMix failed result=%d", result)
            return -1;
        }

        //实例化混音器
        result = (*outputMixObject)->Realize(outputMixObject, SL_BOOLEAN_FALSE);
        if (result != SL_RESULT_SUCCESS) {
            LOGE("outputMixObject Realize failed result=%d", result)
            return -1;
        }

        result = (*outputMixObject)->GetInterface(
                outputMixObject,
                SL_IID_ENVIRONMENTALREVERB,
                &outputMixEnvironmentalReverb);
        if (result != SL_RESULT_SUCCESS) {
            LOGE("outputMixObject GetInterface outputMixEnvironmentalReverb failed result=%d",
                 result)
            return -1;
        }

        SLEnvironmentalReverbSettings reverbSettings = SL_I3DL2_ENVIRONMENT_PRESET_STONECORRIDOR;
        result = (*outputMixEnvironmentalReverb)->SetEnvironmentalReverbProperties(
                outputMixEnvironmentalReverb,
                &reverbSettings);
        if (result != SL_RESULT_SUCCESS) {
            LOGE("outputMixEnvironmentalReverb SetEnvironmentalReverbProperties failed result=%d",
                 result)
            return -1;
        }

        /***********  3 配置音频信息 ***********/
        SLDataLocator_OutputMix outputMix = {SL_DATALOCATOR_OUTPUTMIX, outputMixObject};
        SLDataSink slDataSink = {&outputMix, 0};
        //缓冲队列
        SLDataLocator_AndroidSimpleBufferQueue android_queue = {
                SL_DATALOCATOR_ANDROIDSIMPLEBUFFERQUEUE,
                2};

        //音频格式
        SLDataFormat_PCM pcmFormat = {
                SL_DATAFORMAT_PCM,//播放pcm格式的数据
                2,//声道数
                static_cast<SLuint32>(getCurrentSampleRateForOpensles(sample_rate)),//采样率
                SL_PCMSAMPLEFORMAT_FIXED_16,//采样位数 16位
                SL_PCMSAMPLEFORMAT_FIXED_16,//和采样位数一样就行
                SL_SPEAKER_FRONT_LEFT | SL_SPEAKER_FRONT_RIGHT,//左右声道 立体声
                SL_BYTEORDER_LITTLEENDIAN//字节序，小端
        };
        SLDataSource slDataSource = {&android_queue, &pcmFormat};

        /***********  4 创建播放器 ***********/
        const SLInterfaceID ids[] = {SL_IID_BUFFERQUEUE, SL_IID_VOLUME, SL_IID_MUTESOLO};
        const SLboolean req[] = {SL_BOOLEAN_TRUE, SL_BOOLEAN_TRUE, SL_BOOLEAN_TRUE};

        result = (*engineEngine)->CreateAudioPlayer(engineEngine,
                                                    &pcmPlayerObject,
                                                    &slDataSource,
                                                    &slDataSink,
                                                    sizeof(ids) / sizeof(SLInterfaceID),
                                                    ids,
                                                    req);
        if (result != SL_RESULT_SUCCESS) {
            LOGE("engineEngine CreateAudioPlayer pcmPlayerObject failed result=%d", result)
            return -1;
        }

        //初始化播放器
        result = (*pcmPlayerObject)->Realize(pcmPlayerObject, SL_BOOLEAN_FALSE);
        if (result != SL_RESULT_SUCCESS) {
            LOGE("pcmPlayerObject Realize failed result=%d", result)
            return -1;
        }

        //获取player接口
        result = (*pcmPlayerObject)->GetInterface(pcmPlayerObject, SL_IID_PLAY, &pcmPlayerPlay);
        if (result != SL_RESULT_SUCCESS) {
            LOGE("pcmPlayerObject GetInterface pcmPlayerPlay failed result=%d", result)
            return -1;
        }

        //获取声道接口
        result = (*pcmPlayerObject)->GetInterface(pcmPlayerObject, SL_IID_MUTESOLO, &pcmMutePlay);
        if (result != SL_RESULT_SUCCESS) {
            LOGE("pcmPlayerObject GetInterface pcmMutePlay failed result=%d", result)
            return -1;
        }

        //获取音量接口
        result = (*pcmPlayerObject)->GetInterface(pcmPlayerObject, SL_IID_VOLUME, &pcmVolumePlay);
        if (result != SL_RESULT_SUCCESS) {
            LOGE("pcmPlayerObject GetInterface pcmVolumePlay failed result=%d", result)
            return -1;
        }

        //获取播放队列接口
        result = (*pcmPlayerObject)->GetInterface(pcmPlayerObject, SL_IID_BUFFERQUEUE,
                                                  &pcmBufferQueue);
        if (result != SL_RESULT_SUCCESS) {
            LOGE("pcmPlayerObject GetInterface pcmBufferQueue failed result=%d", result)
            return -1;
        }

        //在子线程中启动播放器
//        pthread_create(&play_thread_t, nullptr, p_play, this);

//
//        /***********  5 设置播放器回调 ***********/
//        result = (*pcmBufferQueue)->RegisterCallback(
//                pcmBufferQueue,
//                pcmBufferCallBack,
//                this);
//        if (result != SL_RESULT_SUCCESS) {
//            LOGE("pcmBufferQueue RegisterCallback failed result=%d", result)
//            return -1;
//        }

        //启动播放器
        play();

//        gettimeofday(&t_end, NULL);
//        LOGI("End time: %ld us", t_end.tv_usec)
//
//        long cost_time = t_end.tv_usec - t_start.tv_usec;
//        LOGI("opensles create cost: %ld ms", cost_time / 1000)
        return 0;
    }


    int AudioPlayer::getCurrentSampleRateForOpensles(int sample_rate) {
        int rate = 0;
        switch (sample_rate) {
            case 8000:
                rate = SL_SAMPLINGRATE_8;
                break;
            case 11025:
                rate = SL_SAMPLINGRATE_11_025;
                break;
            case 12000:
                rate = SL_SAMPLINGRATE_12;
                break;
            case 16000:
                rate = SL_SAMPLINGRATE_16;
                break;
            case 22050:
                rate = SL_SAMPLINGRATE_22_05;
                break;
            case 24000:
                rate = SL_SAMPLINGRATE_24;
                break;
            case 32000:
                rate = SL_SAMPLINGRATE_32;
                break;
            case 44100:
                rate = SL_SAMPLINGRATE_44_1;
                break;
            case 48000:
                rate = SL_SAMPLINGRATE_48;
                break;
            case 64000:
                rate = SL_SAMPLINGRATE_64;
                break;
            case 88200:
                rate = SL_SAMPLINGRATE_88_2;
                break;
            case 96000:
                rate = SL_SAMPLINGRATE_96;
                break;
            case 192000:
                rate = SL_SAMPLINGRATE_192;
                break;
            default:
                rate = SL_SAMPLINGRATE_44_1;
        }
        LOGD("rate %d", rate);
        return rate;
    }

    void AudioPlayer::play() {
        //在子线程中启动播放器
        pthread_create(&play_thread_t, nullptr, p_play, this);

//
//        /***********  5 设置播放器回调 ***********/
//        result = (*pcmBufferQueue)->RegisterCallback(
//                pcmBufferQueue,
//                pcmBufferCallBack,
//                this);
//        if (result != SL_RESULT_SUCCESS) {
//            LOGE("pcmBufferQueue RegisterCallback failed result=%d", result)
//            return -1;
//        }

        //设置播放状态
//        (*pcmPlayerPlay)->SetPlayState(pcmPlayerPlay, SL_PLAYSTATE_PLAYING);
//        //启动
//        pcmBufferCallBack(pcmBufferQueue, this);
    }

    void AudioPlayer::putPcmData(PcmData *pcmData, int size) {
        dataQueue->putPcmData(pcmData);
        LOGI("size is %d queue size is %d", size, dataQueue->getPcmDataSize());
    }

    int AudioPlayer::getPcmDataSize() {
        return dataQueue->getPcmDataSize();
    }

    void AudioPlayer::resume() {
        if (pcmPlayerPlay != nullptr) {
            (*pcmPlayerPlay)->SetPlayState(pcmPlayerPlay, SL_PLAYSTATE_PLAYING);
        }
    }

    void AudioPlayer::pause() {
        if (pcmPlayerPlay != nullptr) {
            (*pcmPlayerPlay)->SetPlayState(pcmPlayerPlay, SL_PLAYSTATE_PAUSED);
        }
    }

    void AudioPlayer::stop() {
        if (pcmPlayerPlay != nullptr) {
            (*pcmPlayerPlay)->SetPlayState(pcmPlayerPlay, SL_PLAYSTATE_STOPPED);
        }
    }

    void AudioPlayer::release() {
        LOGI("OpenSL ES player start release")
        stop();

        if (pcmPlayerObject != NULL) {
            LOGI("pcmPlayerObject start Destroy")
            (*pcmPlayerObject)->Destroy(pcmPlayerObject);
            pcmPlayerObject = NULL;
            pcmPlayerPlay = NULL;
            pcmBufferQueue = NULL;
        }

        if (outputMixObject != NULL) {
            LOGI("outputMixObject start Destroy")
            (*outputMixObject)->Destroy(outputMixObject);
            outputMixObject = NULL;
            outputMixEnvironmentalReverb = NULL;
        }

        if (engineObject != NULL) {
            LOGI("engineObject start Destroy")
            (*engineObject)->Destroy(engineObject);
            engineObject = NULL;
            engineEngine = NULL;
        }

        this->dataQueue->setWork(0);
        this->dataQueue->clearPcmData();
        delete dataQueue;
        dataQueue = NULL;

    }


} // hy